package com.rad.datastat.service;

import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;

import android.app.ActivityManager;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Handler;
import android.os.IBinder;
import android.telephony.TelephonyManager;

import com.rad.datastat.database.AppLaunchDB;
import com.rad.datastat.database.CallAndSmsDB;
import com.rad.datastat.event.AppLaunchEvent;
import com.rad.datastat.event.DailyEvent;
import com.rad.datastat.model.AppLaunchInfo;
import com.rad.datastat.model.CallAndSmsInfo;
import com.rad.datastat.model.LaunchInfo;
import com.rad.datastat.utils.ArrivalPrefs;
import com.rad.datastat.utils.Utils;
import com.rad.net.protocol.android.utils.LogUtils;
import com.rad.statistics.android.StatisticsAgent;

/**
 * 类说明：
 * 
 * @author xinhui.cheng
 * @date 2014-12-12
 * @version 1.0
 */
public class DatastatService extends Service {
	private static final String TAG = DatastatService.class.getSimpleName();
	private static final long INTERVAL = 10000;
	private static final int SECOND = 1000;
	private final static int MAX_SERVICE_INQUERY_NUM = 256;
	private SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
	private SimpleDateFormat mTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
	private Timer mTimer;
	private PackageManager mPm;
	private ActivityManager mActivityManager;
	private Set<String> mLauncherPkgs;
	private String mPreRunAppPkg;
	private String mLauncherTime;
	private long mRunningTime;
	private String mDate;

	private BroadcastReceiver mCallReceiver;
	private ContentObserver mSmsObserver;

	/**
	 *  * 用来判断服务是否运行.  * @param context  * @param className 判断的服务名字  * @return
	 * true 在运行 false 不在运行  
	 */
	public static boolean isServiceRunning(Context context) {
		boolean isRunning = false;
		ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
		List<ActivityManager.RunningServiceInfo> serviceList = activityManager
				.getRunningServices(MAX_SERVICE_INQUERY_NUM);
		if (serviceList.size() == 0) {
			return false;
		}
		for (int i = 0; i < serviceList.size(); i++) {
			if (serviceList.get(i).service.getPackageName().equals(context.getPackageName())
					&& serviceList.get(i).service.getClassName().equals(DatastatService.class.getName())) {
				isRunning = true;
				break;
			}
		}
		return isRunning;
	}

	@Override
	public IBinder onBind(Intent intent) {
		return null;
	}

	@Override
	public void onCreate() {
		super.onCreate();

		// begin watch call
		mCallReceiver = new BroadcastReceiver() {
			@Override
			public void onReceive(Context context, Intent intent) {
				String date = mDateFormat.format(System.currentTimeMillis());
				if (intent.getAction().equals(Intent.ACTION_NEW_OUTGOING_CALL)) {
					// 去电
					CallAndSmsDB.instance(context).updateCallOut(date);
				} else {
					// 来电
					TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
					if (tm.getCallState() == TelephonyManager.CALL_STATE_OFFHOOK) {
						CallAndSmsDB.instance(context).updateCallIn(date);
					}
				}
			}
		};

		IntentFilter filter = new IntentFilter();
		filter.addAction(Intent.ACTION_NEW_OUTGOING_CALL);
		filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
		registerReceiver(mCallReceiver, filter);

		initSmsCount();
		// begin to watch sms
		final ContentResolver resolver = getContentResolver();
		mSmsObserver = new ContentObserver(new Handler()) {
			@Override
			public void onChange(boolean selfChange) {
				super.onChange(selfChange);
				checkSmsCount();
			}
		};
		resolver.registerContentObserver(Uri.parse("content://sms"), true, mSmsObserver);
	}

	@Override
	public void onDestroy() {
		super.onDestroy();

		if (mTimer != null) {
			mTimer.cancel();
			mTimer = null;
		}

		if (mCallReceiver != null) {
			unregisterReceiver(mCallReceiver);
			mCallReceiver = null;
		}
		if (mSmsObserver != null) {
			getContentResolver().unregisterContentObserver(mSmsObserver);
			mSmsObserver = null;
		}
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {

		if (mPm == null) {
			mPm = getPackageManager();
		}
		if (mActivityManager == null) {
			mActivityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
		}
		if (mLauncherPkgs == null) {
			mLauncherPkgs = getLauncherPackageName();
		}

		if (mTimer == null) {
			mTimer = new Timer();
			mTimer.schedule(new AnalyseTask(), 1000, INTERVAL);
		}

		if (Utils.getNetworkInfo(this)[0].equals("wifi")) {
			sendDailyEvent(this);
		}

		return super.onStartCommand(intent, flags, startId);
	}

	private class AnalyseTask extends TimerTask {

		@Override
		public void run() {
			analyseData(DatastatService.this);
		}

	}

	private void analyseData(Context context) {
		String currentRunningAppPkg = null;
		if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.LOLLIPOP) {
			currentRunningAppPkg = getCurrentRunningAppPkg();
		} else {
			currentRunningAppPkg = getCurrentRunningAppPkg(context);
		}
		LogUtils.i("WorkingService", "currentTopAppPkg=" + currentRunningAppPkg);
		if (mPreRunAppPkg == null) {
			if (mLauncherPkgs.contains(currentRunningAppPkg)) {
				return;
			}
			mPreRunAppPkg = currentRunningAppPkg;
			initTime();
		} else {
			if (mPreRunAppPkg.equals(currentRunningAppPkg)) {
				mRunningTime += INTERVAL / SECOND;
			} else {
				AppLaunchInfo info = new AppLaunchInfo();
				info.setDete(mDate);
				info.setLaunchTime(mLauncherTime);
				info.setDuration(mRunningTime);
				info.setPkgName(mPreRunAppPkg);
				AppLaunchDB.instance(context).save(info);

				if (mLauncherPkgs.contains(currentRunningAppPkg)) {
					mPreRunAppPkg = null;
				} else {
					mPreRunAppPkg = currentRunningAppPkg;
				}

				initTime();
			}
		}
	}

	private void initTime() {
		long currentTime = System.currentTimeMillis();
		mDate = mDateFormat.format(currentTime);
		mLauncherTime = mTimeFormat.format(currentTime);
		mRunningTime = INTERVAL / SECOND;
	}

	@SuppressWarnings("deprecation")
	private String getCurrentRunningAppPkg() {
		ComponentName info = null;
		try {
			info = mActivityManager.getRunningTasks(1).get(0).topActivity;
			return info.getPackageName();
		} catch (Exception e) {
			// e.printStackTrace();
		}
		return "";
	}

	// Android5.0之后获取当前启动的app
	public String getCurrentRunningAppPkg(Context context) {
		final int START_TASK_TO_FRONT = 2;
		ActivityManager.RunningAppProcessInfo currentInfo = null;
		Field field = null;
		String pkgName = null;
		try {
			field = ActivityManager.RunningAppProcessInfo.class.getDeclaredField("processState");
			ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
			List<ActivityManager.RunningAppProcessInfo> appList = am.getRunningAppProcesses();
			for (ActivityManager.RunningAppProcessInfo app : appList) {
				if (app.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
					Integer state = field.getInt(app);
					if (state != null && state == START_TASK_TO_FRONT) {
						currentInfo = app;
						break;
					}
				}
			}
			if (currentInfo != null) {
				String[] pkgList = currentInfo.pkgList;
				if (pkgList != null && pkgList.length > 0) {
					pkgName = new String();
					for (int i = 0; i < pkgList.length; i++) {
						if (i == 0) {
							pkgName += pkgList[i];
						} else {
							pkgName += "/" + pkgList[i];
						}

					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return pkgName;
	}

	private Set<String> getLauncherPackageName() {
		Set<String> packageNames = new HashSet<String>();
		final Intent intent = new Intent(Intent.ACTION_MAIN);
		intent.addCategory(Intent.CATEGORY_HOME);
		List<ResolveInfo> resolveInfo = mPm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
		for (ResolveInfo ri : resolveInfo) {
			packageNames.add(ri.activityInfo.packageName);
			LogUtils.i(TAG, "launcher packageName =" + ri.activityInfo.packageName);
		}
		if (packageNames == null || packageNames.size() == 0) {
			return null;
		} else {
			return packageNames;
		}
	}

	private void initSmsCount() {
		if (ArrivalPrefs.getLastSMSId(this) != 0) {
			return;
		}
		Cursor cur = null;
		try {
			cur = getContentResolver().query(Uri.parse("content://sms"), null, null, null, "date desc");

			if (cur.moveToFirst()) {
				int newId = cur.getInt(cur.getColumnIndex("_id"));
				ArrivalPrefs.setLastSMSId(this, newId);
			}
		} catch (Exception e) {
			// 权限不足
		} finally {
			if (cur != null) {
				cur.close();
			}
		}
	}

	private void checkSmsCount() {
		Cursor cur = null;
		try {
			cur = getContentResolver().query(Uri.parse("content://sms"), null, null, null, "date desc");
			int oldId = ArrivalPrefs.getLastSMSId(this);
			if (cur.moveToFirst()) {
				int newId = cur.getInt(cur.getColumnIndex("_id"));
				int type = cur.getInt(cur.getColumnIndex("type"));
				if (newId > oldId) {
					String date = mDateFormat.format(System.currentTimeMillis());
					switch (type) {
					case 1:
						// 接收
						CallAndSmsDB.instance(this).updateSmsIn(date);
						break;
					case 2:
						// 发送
						CallAndSmsDB.instance(this).updateSmsOut(date);
						break;
					default:
						break;
					}
					ArrivalPrefs.setLastSMSId(this, newId);
				}
			}
		} catch (Exception e) {
			// 权限不足
		} finally {
			if (cur != null) {
				cur.close();
			}
		}
	}

	private void sendDailyEvent(Context context) {
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
		String currentDate = dateFormat.format(System.currentTimeMillis());

		ArrayList<String> dateList1 = CallAndSmsDB.instance(context).queryDateBeforeDate(currentDate);
		ArrayList<String> dateList2 = AppLaunchDB.instance(context).queryDateBeforeDate(currentDate);
		if (dateList1.size() == 0 && dateList2.size() == 0) {
			return;
		}
		HashSet<String> set = new HashSet<String>();
		set.addAll(dateList1);
		set.addAll(dateList2);

		for (String date : set) {
			DailyEvent dailyEvent = getDailyEvent(context, date, dateList1, dateList2);
			showDailyEventLog(dailyEvent);
			StatisticsAgent.onEvent(context, dailyEvent);
		}
		CallAndSmsDB.instance(context).delAllBeforeDate(currentDate);
		AppLaunchDB.instance(context).delAllBeforeDate(currentDate);
	}

	private DailyEvent getDailyEvent(Context context, String date, ArrayList<String> dateList1,
			ArrayList<String> dateList2) {
		DailyEvent event = new DailyEvent();
		event.setEventName("daily_event");
		event.setDaytime(date);
		if (dateList1.contains(date)) {
			CallAndSmsInfo info = CallAndSmsDB.instance(context).queryByDate(date);
			if (info != null) {
				event.setSmsIn(info.getSmsIn());
				event.setSmsOut(info.getSmsOut());
				event.setCallIn(info.getCallIn());
				event.setCallOut(info.getCallOut());
			}
		}
		if (dateList2.contains(date)) {
			List<AppLaunchEvent> list = getAppLaunchEventList(context, date);
			event.setAppLaunchList(list);
		}
		return event;
	}

	private List<AppLaunchEvent> getAppLaunchEventList(Context context, String date) {
		List<AppLaunchEvent> eventList = new ArrayList<AppLaunchEvent>();
		ArrayList<AppLaunchInfo> list = AppLaunchDB.instance(context).queryByDate(date);
		if (list != null && list.size() != 0) {
			String currentPkgName = list.get(0).getPkgName();
			AppLaunchEvent event = new AppLaunchEvent();
			event.setPkgName(currentPkgName);
			List<LaunchInfo> launchInfoList = new ArrayList<LaunchInfo>();

			for (int i = 0; i < list.size(); i++) {
				AppLaunchInfo appLaunchInfo = list.get(i);
				LaunchInfo launchInfo = new LaunchInfo();
				if (currentPkgName.equals(appLaunchInfo.getPkgName())) {
					launchInfo.setLuanchTime(appLaunchInfo.getLaunchTime());
					launchInfo.setDuration(appLaunchInfo.getDuration());
					launchInfoList.add(launchInfo);
				} else {
					event.setLaunchList(launchInfoList);
					eventList.add(event);

					event = new AppLaunchEvent();
					launchInfoList = new ArrayList<LaunchInfo>();
					currentPkgName = appLaunchInfo.getPkgName();
					event.setPkgName(currentPkgName);
					launchInfo.setLuanchTime(appLaunchInfo.getLaunchTime());
					launchInfo.setDuration(appLaunchInfo.getDuration());
					launchInfoList.add(launchInfo);
				}
			}
			event.setLaunchList(launchInfoList);
			eventList.add(event);
		}
		return eventList;
	}

	private void showDailyEventLog(DailyEvent dailyEvent) {
		if (!LogUtils.DEBUG) {
			return;
		}
		StringBuffer msg = new StringBuffer("Date=" + dailyEvent.getDaytime() + "\n" + "CallIn="
				+ dailyEvent.getCallIn() + "\n" + "CallOut=" + dailyEvent.getCallOut() + "\n" + "SmsIn="
				+ dailyEvent.getSmsIn() + "\n" + "SmsOut=" + dailyEvent.getSmsOut() + "\n");
		List<AppLaunchEvent> list = dailyEvent.getAppLaunchList();
		for (int i = 0; i < list.size(); i++) {
			AppLaunchEvent e = list.get(i);
			msg.append((i + 1) + "-------------------\n");
			msg.append("pkg=" + e.getPkgName() + "\n");
			List<LaunchInfo> launchList = e.getLaunchList();
			for (int j = 0; j < launchList.size(); j++) {
				LaunchInfo info = launchList.get(j);
				msg.append("[" + info.getLuanchTime() + "," + info.getDuration() + "s]");
			}
			msg.append("\n");
		}
		msg.append("========================\n");
		LogUtils.i("DailyEvent", msg.toString());
	}
}
